/*
 * Copyright (C) 2013 Wojciech Dzierżanowski
 * See LICENSE.txt for licensing details.
 */

package wdzierzan.downstream.core;

import java.io.File;
import java.io.IOException;

public class DefaultTargetFileFactory implements TargetFileFactory {

    private static class DefaultTargetFile implements TargetFile {
        private final File realFile;
        private File file;

        public DefaultTargetFile(File realFile) throws IOException {
            this.realFile = realFile;
            this.file = File.createTempFile("downstream-", "", realFile.getParentFile());
        }

        public File getFile() {
            return file;
        }

        public String getPath() {
            return getFile().getPath();
        }

        public void commit() throws IOException {
            if (!file.renameTo(realFile))
                throw new IOException("Failed to commit target file");
            file = realFile;
        }

        public void release() {
            if (file != realFile)
                // not committed
                file.delete();
            file = null;
        }
    }

    private static class DefaultTargetDirectory implements TargetFile {
        private final File realDirectory;
        private File directory;

        public DefaultTargetDirectory(File directory) throws IOException {
            this.realDirectory = directory;

            if (realDirectory.exists()) {
                this.directory = realDirectory;
            } else {
                this.directory = File.createTempFile("downstream-", "", realDirectory.getParentFile());
                if (!this.directory.delete() || !this.directory.mkdir())
                    throw new IOException("Failed to create temporary directory");
            }
        }

        public File getFile() {
            return directory;
        }

        public String getPath() {
            return getFile().getPath();
        }

        public void commit() throws IOException {
            if (directory != realDirectory && !directory.renameTo(realDirectory)) {
                FileUtils.deleteRecursively(directory);
                throw new IOException("Failed to commit target directory");
            }
            directory = realDirectory;
        }

        public void release() {
            if (directory != realDirectory) {
                // Not committed.  Have to behave as if committed if the directory has any files.
                String[] children = directory.list();
                if (children != null && children.length > 0)
                    directory.renameTo(realDirectory);
                else
                    directory.delete();
            }
            directory = null;
        }
    }

    public TargetFile getTargetFile(File file) throws IOException {
        return new DefaultTargetFile(file);
    }

    public TargetFile getTargetFile(String path) throws IOException {
        return getTargetFile(new File(path));
    }

    public TargetFile getTargetDirectory(File directory) throws IOException {
        return new DefaultTargetDirectory(directory);
    }
}
